/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package com.example.touch.wifipositioning;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

public class FingerPrintingNN implements IWifiPositioner {

	public PositionCalculationResult CalculatePosition(List<TraceEntry> offlineTraces, TraceEntry onlineTrace) {
		HashMap<MACAddress, ArrayList<TraceEntry>> index = new HashMap<MACAddress, ArrayList<TraceEntry>>();
		
		// Init HashMap with macadresses as keys and a list of entries that
		// 'sees' the macadress as the value
		for (TraceEntry entry : offlineTraces) {
			SignalStrengthSamples s = entry.getSignalStrengthSamples();
			for (MACAddress m : s.getSortedAccessPoints()) {
				if (index.containsKey(m) == false) {
					index.put(m, new ArrayList<TraceEntry>());
				}
				index.get(m).add(entry);
			}
		}

		// Find the best fitted offline entry for all the online entries
		HashSet<TraceEntry> entries = new HashSet<TraceEntry>();
		// Get all the offline entries that 'sees' the same AP's as the current
		// online entry
		for (MACAddress m : onlineTrace.getSignalStrengthSamples().getSortedAccessPoints()) {
			if (index.containsKey(m)) {
				for (TraceEntry offlineEntry : index.get(m)) {
					if (entries.contains(offlineEntry) == false)
						entries.add(offlineEntry);
				}
			}
		}

		double minDistance = Double.MAX_VALUE;
		TraceEntry bestEntry = null;

		// Get the offline entry with the least euclidean signal strength
		// distance
		for (TraceEntry offline : entries) {
			double distance = DistanceCalculator.calcDistance(offline, onlineTrace, 4);
			if (distance < minDistance) {
				bestEntry = offline;
				minDistance = distance;
			}
		}
		
		if(bestEntry == null){
			return null;
		}

		// Add the best fitted offline entry and the online entry to the list
		PositionCalculationResult result = new PositionCalculationResult(bestEntry.getPosition(), onlineTrace.getPosition());
		return result;
	}

}
